package cn.xiaohuodui.service.shiro;

import cn.xiaohuodui.constant.ErrorCodeDefine;
import cn.xiaohuodui.dao.AdminMapper;
import cn.xiaohuodui.dao.PermissionMapper;
import cn.xiaohuodui.dao.RoleMapper;
import cn.xiaohuodui.dto.PermissionDto;
import cn.xiaohuodui.model.Admin;
import cn.xiaohuodui.model.Permission;
import cn.xiaohuodui.model.Role;
import cn.xiaohuodui.utils.BCrypt;
import cn.xiaohuodui.vo.admin.AdminVo;
import cn.xiaohuodui.vo.admin.RoleVo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SmallFireShiroRealm extends AuthorizingRealm {
    private static final Log logger = LogFactory.getLog(SmallFireShiroRealm.class);

    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    PermissionMapper permissionMapper;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        AdminVo admin = (AdminVo) principals.getPrimaryPrincipal();
        for (RoleVo role : admin.getRoles()) {
            authorizationInfo.addRole(role.getRole());
            for (Permission p : role.getPermissions()) {
                authorizationInfo.addStringPermission(p.getPermission());
            }
        }
        logger.info("adminId:" + admin.getId() + ",permission:" + authorizationInfo.getStringPermissions());
        return authorizationInfo;
    }

    /*主要是用来进行身份认证的，也就是说验证用户输入的账号和密码是否正确。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        String username = usernamePasswordToken.getUsername();
        String password = String.valueOf(usernamePasswordToken.getPassword());

        Admin admin = adminMapper.selectByUsername(username);
        if (admin == null) {
            throw new AuthenticationException(ErrorCodeDefine.DEFAULT_ERROR.getDesc());
        }
        if (!BCrypt.hashpw(password, admin.getSalt()).equals(admin.getPassword())) {
            throw new AuthenticationException(ErrorCodeDefine.PASSWORD_NOT_VALID.getDesc());
        }

        //获取权限
        AdminVo adminVo = new AdminVo();
        BeanUtils.copyProperties(admin, adminVo);

        List<Role> roleList = roleMapper.selectByAdminId(admin.getId());
        if (!CollectionUtils.isEmpty(roleList)) {
            List<Integer> roleIds = roleList.stream().map(x -> x.getId()).collect(Collectors.toList());

            List<PermissionDto> permissions = permissionMapper.selectByRoleIds(roleIds);
            Map<Integer, List<PermissionDto>> idToGroupMap = permissions.stream().collect(Collectors.groupingBy(PermissionDto::getRoleId));

            adminVo.setRoles(roleList.stream().map(
                    role -> {
                        RoleVo roleVo = new RoleVo();
                        BeanUtils.copyProperties(role, roleVo);
                        List<PermissionDto> permissionDtos = idToGroupMap.get(role.getId());
                        roleVo.setPermissions(CollectionUtils.isEmpty(permissionDtos) ? new ArrayList<>() : permissionDtos);
                        return roleVo;
                    }
            ).collect(Collectors.toList()));
        } else {
            adminVo.setRoles(new ArrayList<>());
        }
        return new SimpleAuthenticationInfo(adminVo, password, getName());
    }
}